package marchsoft.modules.four.admin.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import marchsoft.base.BasicServiceImpl;
import marchsoft.base.PageVO;
import marchsoft.enums.ResultEnum;
import marchsoft.exception.BadRequestException;
import marchsoft.modules.four.admin.entity.dto.RepositoryDTO;
import marchsoft.modules.four.admin.mapper.ReMapper;
import marchsoft.modules.four.admin.mapper.SafeTypeMapper;
import marchsoft.modules.four.admin.service.ReService;
import marchsoft.modules.four.admin.service.mapstruct.RepositoryMapstruct;
import marchsoft.modules.four.common.entity.Repository;
import marchsoft.modules.four.common.mapper.MapperRepository;
import marchsoft.modules.four.common.utils.BaseUtils;
import marchsoft.modules.four.admin.entity.dto.RepositoryDTOH5;
import marchsoft.utils.FileUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.stereotype.Service;
import org.springframework.beans.factory.annotation.Value;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.time.LocalDateTime;
import java.util.*;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.*;

import java.util.stream.Collectors;


@Service
@RequiredArgsConstructor
public class ReServiceImpl extends BasicServiceImpl<MapperRepository, Repository> implements ReService {


    private final RepositoryMapstruct repositoryMapstruct;
    private final ReMapper mapper;
    private final SafeTypeMapper safeTypeMapper;
    private List<Repository> eRepositoryList;
    private final ReMapper eRepositoryMapper;
    private int errorNum;
    @Value("${file.path}")
    private String filePath;


    @Override //分类条件查询题库
    public IPage<Repository> queryAll1(PageVO pageVO, RepositoryDTO repositoryDTO) {
        IPage<Repository> page = new Page<>(pageVO.getCurrent(), pageVO.getSize());
        QueryWrapper<Repository> queryWrapper = new QueryWrapper<>();
        String safeTypeName = repositoryDTO.getSafeTypeName();
        System.out.println(repositoryDTO);
        if (safeTypeName != null){
            Long id = mapper.selectID(safeTypeName);
            if (0 != id){
                queryWrapper.eq("safe_type_id",id);
            }
        }

        Integer quesType = repositoryDTO.getQuesType();
        if (quesType != null){
            queryWrapper.eq("ques_type",quesType);
        }

        String quesContent = repositoryDTO.getQuesContent();
        if (quesContent != null){
            queryWrapper.eq("ques_content",quesContent);
        }
        LocalDateTime startTime = repositoryDTO.getStartTime();
        LocalDateTime endTime = repositoryDTO.getEndTime();
        if (startTime != null && endTime != null){
            queryWrapper.between("create_time",startTime,endTime);
        }

        queryWrapper.orderByDesc("create_time");
        return page(page, queryWrapper);
    }

//    @Override//查询所有安全分类名称
//    public List<SafeType> selectAllName() {
//        return safeTypeMapper.selectAllSafeTypeName();
//    }

    @Override//新增题库
    public void insertRE(Repository repository) {
        save(repository);

    }

    @Override//更新题库
    public void updateRe(Repository repository) {
        updateById(repository);
    }

    @Override//根据id删除
    public void deleteRe(List<Integer> id) {
        removeByIds(id);
    }


    @Override
    public void importRepository(MultipartFile file, HttpServletResponse res) {
        eRepositoryList = new ArrayList<>();
        if (!file.isEmpty()) {
            try {
                //excel 文件
                XSSFWorkbook workbook = new XSSFWorkbook(file.getInputStream());
                //excel 工作表
                XSSFSheet sheet = workbook.getSheetAt(0);
                //空值判断和数据插入表中
                judgeNullValue(sheet);
                if (errorNum > 0) {
                    String fileName = "errorRepositoryLog.xlsx";
                    File fileDir = new File(filePath);
                    if (!fileDir.exists()) {
                        fileDir.mkdirs();
                    }
                    // 保存excel文件到服务器
                    workbook.write(new FileOutputStream(filePath + "DIS" + fileName));
                    workbook.close();
                    log.error("【题目模板填写有误，请看" + filePath + "DIS" + fileName + "处的文件中具体注释!】");
                    BaseUtils.errorLog(ResultEnum.OPERATION_FAIL, "DIS" + fileName, "【题目模板填写有误，请看该位置文件中的注释!】" + filePath + "DIS" + fileName);
                }
                if (errorNum == 0) {
                    eRepositoryMapper.insertAllBatch(eRepositoryList);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            return;
        }
        log.error("请上传文件！");
        throw new BadRequestException("请上传文件！");
    }

    @Override
    public List<RepositoryDTOH5> queryAll(RepositoryDTOH5 repositoryDTOH5) {
        List<Repository> depts = mapper.selectList(analysisQueryCriteria(repositoryDTOH5));
        return repositoryMapstruct.toDto(depts);
    }

    @Override
    public LambdaQueryWrapper<Repository> analysisQueryCriteria(RepositoryDTOH5 repositoryDTOH5) {
        System.out.println(repositoryDTOH5);
        LambdaQueryWrapper<Repository> wrapper = new LambdaQueryWrapper<>();
        String safeTypeName = repositoryDTOH5.getSafeTypeName();
        if (safeTypeName != null){
            Long id = mapper.selectID(repositoryDTOH5.getSafeTypeName());
            if (0 != id){
                wrapper.eq(Repository::getSafeTypeId,id);
            }
        }
        Integer quesType = repositoryDTOH5.getQuesType();
        if (quesType != null){
            wrapper.eq(Repository::getQuesType,quesType);
        }
        String quesContent = repositoryDTOH5.getQuesContent();
        if (quesContent != null){
            wrapper.eq(Repository::getQuesContent,quesContent);
        }
        LocalDateTime startTime = repositoryDTOH5.getStartTime();
        LocalDateTime endTime = repositoryDTOH5.getEndTime();
        if (startTime != null && endTime != null){
            wrapper.between(Repository::getCreateTime, startTime,
                    ObjectUtil.isNull(repositoryDTOH5.getEndTime()) ? LocalDateTime.now() : repositoryDTOH5.getEndTime());
        }
        System.out.println(wrapper);
        return wrapper;
    }

    @Override
    public void download(List<RepositoryDTOH5> queryAll, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (RepositoryDTOH5 repositoryDTO:queryAll){
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("安全分类",repositoryDTO.getSafeTypeId());
            map.put("题型(1:单选 2:多选 3:判断)",repositoryDTO.getQuesType());
            map.put("题干",repositoryDTO.getQuesContent());
            map.put("选项",repositoryDTO.getOptions());
            map.put("答案",repositoryDTO.getAnswer());
            list.add(map);

        }
        FileUtils.downloadExcel(list, response);
    }


    /**
     * 错误信息描述(添加注释、设置单元格背景颜色)
     *
     * @param cell
     * @param error
     */
    public void recordErrorCell(Cell cell, String error) {
        errorNum++;
        Workbook workbook = cell.getSheet().getWorkbook();
        Sheet sheet = cell.getSheet();
        Drawing draw = sheet.createDrawingPatriarch();
        CreationHelper factory = sheet.getWorkbook().getCreationHelper();
        ClientAnchor anchor = factory.createClientAnchor();
        //前四个参数是坐标点,后四个参数是编辑和显示批注时的大小.
        Comment comment = draw.createCellComment(anchor);
        comment.setString(new XSSFRichTextString(error));  //设置批注内容
        //将批注添加到单元格对象中
        cell.setCellComment(comment);
        CellStyle cellStyle = workbook.createCellStyle();
        cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());  // 背景色
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cell.setCellStyle(cellStyle);
        //设置样式格式，设置发生错误时。要设置的单元格背景颜色
        cellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());  // 背景色
        cellStyle.setFillPattern(FillPatternType.SOLID_FOREGROUND);
        cell.setCellStyle(cellStyle);
    }

    /**
     * 初始化单元格样式、注释和格式
     *
     * @param sheet
     */
    public void formatCell(XSSFSheet sheet) {
        Workbook workbook = sheet.getWorkbook();
        if (sheet.getRow(1) != null) {
            //遍历列
            for (int a = 0; a < sheet.getRow(1).getPhysicalNumberOfCells(); a++) {
                //遍历列所在行
                for (int i = 0; i < sheet.getLastRowNum() + 1; i++) {
                    //为所有单元格设置为有单元格
                    Cell cell = sheet.getRow(i).getCell(a);
                    //设置默认值和样式
                    if (ObjectUtil.isNotNull(cell)) {
                        CellStyle cellStyle = workbook.createCellStyle();
                        // 背景色
                        cellStyle.setFillPattern(FillPatternType.NO_FILL);
                        cell.setCellStyle(cellStyle);
                        //移除注释
                        cell.removeCellComment();
                    }
                }
            }
        } else {
            Row row1 = sheet.createRow(1);
            Cell cell1 = row1.createCell(0);
            recordErrorCell(cell1, "该行不能为空！");
            log.error("该行不能为空！");
        }
    }

    /**
     * 空值判断和数据校验
     *
     * @param sheet
     */
    public void judgeNullValue(XSSFSheet sheet) {
        errorNum = 0;
        formatCell(sheet);
        int index = 1;
        String[] stringArray = {"全民国家安全", "等碱金属", "电子邮箱"};
        for (String s : stringArray) {
            if (sheet.getRow(index) == null) {
                sheet.createRow(index);
            }
            if (sheet.getRow(index).getCell(1) == null) {
                sheet.getRow(index).createCell(1);
            }
            if (sheet.getRow(index).getCell(1).getStringCellValue().contains(s)) {
                index++;
            }
        }
        System.out.println(sheet.getLastRowNum());
        if (index > sheet.getLastRowNum()) {
            log.error("该行不能为空");
            String errorString = "该行不能为空！";
            if (sheet.getRow(index) == null) {
                sheet.createRow(index);
                if (sheet.getRow(index).getCell(0) == null) {
                    sheet.getRow(index).createCell(0);
                }
            }
            XSSFCell kongCell = sheet.getRow(index).getCell(0);
            recordErrorCell(kongCell, errorString);
            return;
        }

        for (int i = index; i < sheet.getLastRowNum() + 1; i++) {
            Repository eRepository = new Repository();
            XSSFRow row = sheet.getRow(i);
            //如果该行不为空行
            if (row != null && !isRowEmpty(row)) {
                Cell quesTypeCell = row.getCell(0);
                Cell quesContentCell = row.getCell(1);
                Cell optionsCell = row.getCell(2);
                Cell answerCell = row.getCell(3);
                Cell safeTypeCell = row.getCell(4);
                //初始化单元格格式为文本类型
                List<Cell> cellList = new ArrayList<>();
                cellList.add(quesTypeCell);
                cellList.add(quesContentCell);
                cellList.add(optionsCell);
                cellList.add(answerCell);
                cellList.add(safeTypeCell);
                for (int j = 0; j < cellList.size(); j++) {
                    if (cellList.get(j) == null) {
                        cellList.set(j, row.createCell(j));
                        if (!cellList.get(j).getCellTypeEnum().equals(CellType.STRING)) {
                            cellList.get(j).setCellType(CellType.STRING);
                        }
                    } else {
                        if (!cellList.get(j).getCellTypeEnum().equals(CellType.STRING)) {
                            cellList.get(j).setCellType(CellType.STRING);
                        }
                    }
                }

                String quesContent = cellList.get(1).getStringCellValue();
                String options = cellList.get(2).getStringCellValue();
                String answer = cellList.get(3).getStringCellValue();
                String safeType = cellList.get(4).getStringCellValue();

                //空值判断
                if (StrUtil.isEmpty(safeType)) {
//                repositoryFalse = false;
                    recordErrorCell(cellList.get(4), "题目所属分类不能为空！");
                    log.error("题目所属分类不能为空！");
                } else {
                    //根据分类名称查询分类id
                    Long safeTypeId =eRepositoryMapper.selectID(safeType);
                    if (safeTypeId == null) {
                        recordErrorCell(cellList.get(4), "题目所属分类不存在！请先在系统中添加该安全分类！");
                        log.error("题目所属分类不存在！请先在系统中添加该安全分类！");
                    } else {
                        eRepository.setSafeTypeId(safeTypeId);
                    }
                }
                if (StrUtil.isEmpty(quesContent)) {
//                repositoryFalse = false;
                    recordErrorCell(cellList.get(1), "题干不能为空！");
                    log.error("题干不能为空！");
                } else {
                    eRepository.setQuesContent(quesContent);
                }
                if (StrUtil.isEmpty(options)) {
//                repositoryFalse = false;
                    recordErrorCell(cellList.get(2), "选项不能为空！");
                    log.error("选项不能为空！");
                } else {
                    eRepository.setOptions(options);
                }
                if (StrUtil.isEmpty(answer)) {
//                repositoryFalse = false;
                    recordErrorCell(cellList.get(3), "答案不能为空！");
                    log.error("答案不能为空！");
                } else {
                    eRepository.setAnswer(answer);
                    //多选题：2
                    if (answer.length() > 1) {
                        eRepository.setQuesType(2);
                    }
                    if (answer.length() == 1) {
                        //单选1或判断3
                        if ("Y".equals(answer) || "N".equals(answer)) {
                            eRepository.setQuesType(3);
                        }
                        if ("A".equals(answer) || "B".equals(answer) || "C".equals(answer) || "D".equals(answer)) {
                            eRepository.setQuesType(1);
                        }
                    }
                }
                Long repositoryCount = Long.valueOf(eRepositoryMapper.selectCount(null));
                //若题库表中有记录
                if (repositoryCount > 0) {
                    LambdaQueryWrapper<Repository> wrapper = new LambdaQueryWrapper<>();
                    wrapper.eq(Repository::getQuesContent, quesContent)
                            .eq(Repository::getDeleted, false);
                    List<Repository> eRepositories = eRepositoryMapper.selectList(wrapper);
                    //若数据库的题库表中有题干相同的题
                    if (eRepositories.size() > 0) {
                        log.error("数据库中此题目已存在，请勿重复添加！");
                        XSSFCell cell1 = sheet.getRow(i).getCell(1);
                        //给表中的错误信息添加注释
                        String errorString = "该题目已存在数据库中，请勿重复添加！";
                        recordErrorCell(cell1, errorString);
                    }
                }
                eRepository.setCheck(true);

                eRepository.setDeleted(false);
                if (eRepository != null) {
                    eRepositoryList.add(eRepository);
                }
            } else {
                //若该行为空行
                log.error("该行不能为空");
                String errorString = "该行不能为空！";
                if (sheet.getRow(i) == null) {
                    sheet.createRow(i);
                }
                if (sheet.getRow(i).getCell(0) == null) {
                    sheet.getRow(i).createCell(0);
                }
                XSSFCell kongCell = sheet.getRow(i).getCell(0);
                recordErrorCell(kongCell, errorString);
                break;
            }
        }
        //为了判断excel中是否有同一题目的记录（题干内容相同）
        if (eRepositoryList.size() > 0) {
            //根据题干属性分组
            Map<String, Long> collectMap = eRepositoryList.stream().filter(o -> o.getQuesContent() != null).collect(Collectors.groupingBy(
                    o -> o.getQuesContent(), Collectors.counting()));
            Set<String> keys = collectMap.keySet();
            for (String key : keys) {
                Long valueCount = collectMap.get(key);
                //如果excel中有重复题目
                if (valueCount > 1) {
                    if (null != key && !key.equals("")) {
                        String sameQuesContent = key;
                        for (int k = 1; k < sheet.getLastRowNum() + 1; k++) {
                            XSSFRow row1 = sheet.getRow(k);
                            if (isRowEmpty(row1)) {
                                break;
                            }
                            if (row1 != null && !isRowEmpty(row1)) {
                                Cell quesContentCell = row1.getCell(1);
                                if (quesContentCell != null) {
                                    String quesContent = quesContentCell.getStringCellValue();
                                    if (!quesContent.equals("")) {
                                        if (quesContent.equals(sameQuesContent)) {
                                            recordErrorCell(quesContentCell, "此excel文件中该题目重复，请仅保留一个！");
                                            log.error("此excel文件中该题目重复，请仅保留一个！(excel中有重复数据 --> 题干相同的记录有多条。)");
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    /**
     * 判断该行是否为空行
     *
     * @param row
     * @return
     */
    public static boolean isRowEmpty(Row row) {
        for (int c = row.getFirstCellNum(); c < row.getLastCellNum(); c++) {
            Cell cell = row.getCell(c);
            if (cell != null && !cell.getCellTypeEnum().equals(CellType.BLANK)) {
                return false;
            }
        }
        return true;
    }


}
